@wazir-dev/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +111 -0
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +101 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/assets/composition-engine.mmd +34 -0
- package/assets/demo-script.sh +17 -0
- package/assets/logo-dark.svg +14 -0
- package/assets/logo.svg +14 -0
- package/assets/pipeline.mmd +39 -0
- package/assets/record-demo.sh +51 -0
- package/docs/README.md +51 -0
- package/docs/adapters/context-mode.md +60 -0
- package/docs/concepts/architecture.md +87 -0
- package/docs/concepts/artifact-model.md +60 -0
- package/docs/concepts/composition-engine.md +36 -0
- package/docs/concepts/indexing-and-recall.md +160 -0
- package/docs/concepts/observability.md +41 -0
- package/docs/concepts/roles-and-workflows.md +59 -0
- package/docs/concepts/terminology-policy.md +27 -0
- package/docs/getting-started/01-installation.md +78 -0
- package/docs/getting-started/02-first-run.md +102 -0
- package/docs/getting-started/03-adding-to-project.md +15 -0
- package/docs/getting-started/04-host-setup.md +15 -0
- package/docs/guides/ci-integration.md +15 -0
- package/docs/guides/creating-skills.md +15 -0
- package/docs/guides/expertise-module-authoring.md +15 -0
- package/docs/guides/hook-development.md +15 -0
- package/docs/guides/memory-and-learnings.md +34 -0
- package/docs/guides/multi-host-export.md +15 -0
- package/docs/guides/troubleshooting.md +101 -0
- package/docs/guides/writing-custom-roles.md +15 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
- package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
- package/docs/readmes/INDEX.md +99 -0
- package/docs/readmes/features/expertise/README.md +171 -0
- package/docs/readmes/features/exports/README.md +222 -0
- package/docs/readmes/features/hooks/README.md +103 -0
- package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
- package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
- package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
- package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
- package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
- package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
- package/docs/readmes/features/hooks/session-start.md +119 -0
- package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
- package/docs/readmes/features/roles/README.md +157 -0
- package/docs/readmes/features/roles/clarifier.md +152 -0
- package/docs/readmes/features/roles/content-author.md +190 -0
- package/docs/readmes/features/roles/designer.md +193 -0
- package/docs/readmes/features/roles/executor.md +184 -0
- package/docs/readmes/features/roles/learner.md +210 -0
- package/docs/readmes/features/roles/planner.md +182 -0
- package/docs/readmes/features/roles/researcher.md +164 -0
- package/docs/readmes/features/roles/reviewer.md +184 -0
- package/docs/readmes/features/roles/specifier.md +162 -0
- package/docs/readmes/features/roles/verifier.md +215 -0
- package/docs/readmes/features/schemas/README.md +178 -0
- package/docs/readmes/features/skills/README.md +63 -0
- package/docs/readmes/features/skills/brainstorming.md +96 -0
- package/docs/readmes/features/skills/debugging.md +148 -0
- package/docs/readmes/features/skills/design.md +120 -0
- package/docs/readmes/features/skills/prepare-next.md +109 -0
- package/docs/readmes/features/skills/run-audit.md +159 -0
- package/docs/readmes/features/skills/scan-project.md +109 -0
- package/docs/readmes/features/skills/self-audit.md +176 -0
- package/docs/readmes/features/skills/tdd.md +137 -0
- package/docs/readmes/features/skills/using-skills.md +92 -0
- package/docs/readmes/features/skills/verification.md +120 -0
- package/docs/readmes/features/skills/writing-plans.md +104 -0
- package/docs/readmes/features/tooling/README.md +320 -0
- package/docs/readmes/features/workflows/README.md +186 -0
- package/docs/readmes/features/workflows/author.md +181 -0
- package/docs/readmes/features/workflows/clarify.md +154 -0
- package/docs/readmes/features/workflows/design-review.md +171 -0
- package/docs/readmes/features/workflows/design.md +169 -0
- package/docs/readmes/features/workflows/discover.md +162 -0
- package/docs/readmes/features/workflows/execute.md +173 -0
- package/docs/readmes/features/workflows/learn.md +167 -0
- package/docs/readmes/features/workflows/plan-review.md +165 -0
- package/docs/readmes/features/workflows/plan.md +170 -0
- package/docs/readmes/features/workflows/prepare-next.md +167 -0
- package/docs/readmes/features/workflows/review.md +169 -0
- package/docs/readmes/features/workflows/run-audit.md +191 -0
- package/docs/readmes/features/workflows/spec-challenge.md +159 -0
- package/docs/readmes/features/workflows/specify.md +160 -0
- package/docs/readmes/features/workflows/verify.md +177 -0
- package/docs/readmes/packages/README.md +50 -0
- package/docs/readmes/packages/ajv.md +117 -0
- package/docs/readmes/packages/context-mode.md +118 -0
- package/docs/readmes/packages/gray-matter.md +116 -0
- package/docs/readmes/packages/node-test.md +137 -0
- package/docs/readmes/packages/yaml.md +112 -0
- package/docs/reference/configuration-reference.md +159 -0
- package/docs/reference/expertise-index.md +52 -0
- package/docs/reference/git-flow.md +43 -0
- package/docs/reference/hooks.md +87 -0
- package/docs/reference/host-exports.md +50 -0
- package/docs/reference/launch-checklist.md +172 -0
- package/docs/reference/marketplace-listings.md +76 -0
- package/docs/reference/release-process.md +34 -0
- package/docs/reference/roles-reference.md +77 -0
- package/docs/reference/skills.md +33 -0
- package/docs/reference/templates.md +29 -0
- package/docs/reference/tooling-cli.md +94 -0
- package/docs/truth-claims.yaml +222 -0
- package/expertise/PROGRESS.md +63 -0
- package/expertise/README.md +18 -0
- package/expertise/antipatterns/PROGRESS.md +56 -0
- package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
- package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
- package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
- package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
- package/expertise/antipatterns/backend/index.md +24 -0
- package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
- package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
- package/expertise/antipatterns/code/async-antipatterns.md +622 -0
- package/expertise/antipatterns/code/code-smells.md +1186 -0
- package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
- package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
- package/expertise/antipatterns/code/index.md +27 -0
- package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
- package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
- package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
- package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
- package/expertise/antipatterns/design/dark-patterns.md +1121 -0
- package/expertise/antipatterns/design/index.md +22 -0
- package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
- package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
- package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
- package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
- package/expertise/antipatterns/frontend/index.md +23 -0
- package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
- package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
- package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
- package/expertise/antipatterns/index.md +31 -0
- package/expertise/antipatterns/performance/index.md +20 -0
- package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
- package/expertise/antipatterns/performance/premature-optimization.md +623 -0
- package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
- package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
- package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
- package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
- package/expertise/antipatterns/process/index.md +23 -0
- package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
- package/expertise/antipatterns/security/index.md +20 -0
- package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
- package/expertise/antipatterns/security/security-theater.md +843 -0
- package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
- package/expertise/architecture/PROGRESS.md +70 -0
- package/expertise/architecture/data/caching-architecture.md +671 -0
- package/expertise/architecture/data/data-consistency.md +574 -0
- package/expertise/architecture/data/data-modeling.md +536 -0
- package/expertise/architecture/data/event-streams-and-queues.md +634 -0
- package/expertise/architecture/data/index.md +25 -0
- package/expertise/architecture/data/search-architecture.md +663 -0
- package/expertise/architecture/data/sql-vs-nosql.md +708 -0
- package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
- package/expertise/architecture/decisions/build-vs-buy.md +616 -0
- package/expertise/architecture/decisions/index.md +23 -0
- package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
- package/expertise/architecture/decisions/technology-selection.md +616 -0
- package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
- package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
- package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
- package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
- package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
- package/expertise/architecture/distributed/index.md +25 -0
- package/expertise/architecture/distributed/saga-pattern.md +797 -0
- package/expertise/architecture/foundations/architectural-thinking.md +460 -0
- package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
- package/expertise/architecture/foundations/design-principles-solid.md +649 -0
- package/expertise/architecture/foundations/domain-driven-design.md +719 -0
- package/expertise/architecture/foundations/index.md +25 -0
- package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
- package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
- package/expertise/architecture/index.md +34 -0
- package/expertise/architecture/integration/api-design-graphql.md +638 -0
- package/expertise/architecture/integration/api-design-grpc.md +804 -0
- package/expertise/architecture/integration/api-design-rest.md +892 -0
- package/expertise/architecture/integration/index.md +25 -0
- package/expertise/architecture/integration/third-party-integration.md +795 -0
- package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
- package/expertise/architecture/integration/websockets-realtime.md +791 -0
- package/expertise/architecture/mobile-architecture/index.md +22 -0
- package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
- package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
- package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
- package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
- package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
- package/expertise/architecture/patterns/event-driven.md +797 -0
- package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
- package/expertise/architecture/patterns/index.md +27 -0
- package/expertise/architecture/patterns/layered-architecture.md +736 -0
- package/expertise/architecture/patterns/microservices.md +753 -0
- package/expertise/architecture/patterns/modular-monolith.md +692 -0
- package/expertise/architecture/patterns/monolith.md +626 -0
- package/expertise/architecture/patterns/plugin-architecture.md +735 -0
- package/expertise/architecture/patterns/serverless.md +780 -0
- package/expertise/architecture/scaling/database-scaling.md +615 -0
- package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
- package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
- package/expertise/architecture/scaling/index.md +24 -0
- package/expertise/architecture/scaling/multi-tenancy.md +800 -0
- package/expertise/architecture/scaling/stateless-design.md +787 -0
- package/expertise/backend/embedded-firmware.md +625 -0
- package/expertise/backend/go.md +853 -0
- package/expertise/backend/index.md +24 -0
- package/expertise/backend/java-spring.md +448 -0
- package/expertise/backend/node-typescript.md +625 -0
- package/expertise/backend/python-fastapi.md +724 -0
- package/expertise/backend/rust.md +458 -0
- package/expertise/backend/solidity.md +711 -0
- package/expertise/composition-map.yaml +443 -0
- package/expertise/content/foundations/content-modeling.md +395 -0
- package/expertise/content/foundations/editorial-standards.md +449 -0
- package/expertise/content/foundations/index.md +24 -0
- package/expertise/content/foundations/microcopy.md +455 -0
- package/expertise/content/foundations/terminology-governance.md +509 -0
- package/expertise/content/index.md +34 -0
- package/expertise/content/patterns/accessibility-copy.md +518 -0
- package/expertise/content/patterns/index.md +24 -0
- package/expertise/content/patterns/notification-content.md +433 -0
- package/expertise/content/patterns/sample-content.md +486 -0
- package/expertise/content/patterns/state-copy.md +439 -0
- package/expertise/design/PROGRESS.md +58 -0
- package/expertise/design/disciplines/dark-mode-theming.md +577 -0
- package/expertise/design/disciplines/design-systems.md +595 -0
- package/expertise/design/disciplines/index.md +25 -0
- package/expertise/design/disciplines/information-architecture.md +800 -0
- package/expertise/design/disciplines/interaction-design.md +788 -0
- package/expertise/design/disciplines/responsive-design.md +552 -0
- package/expertise/design/disciplines/usability-testing.md +516 -0
- package/expertise/design/disciplines/user-research.md +792 -0
- package/expertise/design/foundations/accessibility-design.md +796 -0
- package/expertise/design/foundations/color-theory.md +797 -0
- package/expertise/design/foundations/iconography.md +795 -0
- package/expertise/design/foundations/index.md +26 -0
- package/expertise/design/foundations/motion-and-animation.md +653 -0
- package/expertise/design/foundations/rtl-design.md +585 -0
- package/expertise/design/foundations/spacing-and-layout.md +607 -0
- package/expertise/design/foundations/typography.md +800 -0
- package/expertise/design/foundations/visual-hierarchy.md +761 -0
- package/expertise/design/index.md +32 -0
- package/expertise/design/patterns/authentication-flows.md +474 -0
- package/expertise/design/patterns/content-consumption.md +789 -0
- package/expertise/design/patterns/data-display.md +618 -0
- package/expertise/design/patterns/e-commerce.md +1494 -0
- package/expertise/design/patterns/feedback-and-states.md +642 -0
- package/expertise/design/patterns/forms-and-input.md +819 -0
- package/expertise/design/patterns/gamification.md +801 -0
- package/expertise/design/patterns/index.md +31 -0
- package/expertise/design/patterns/microinteractions.md +449 -0
- package/expertise/design/patterns/navigation.md +800 -0
- package/expertise/design/patterns/notifications.md +705 -0
- package/expertise/design/patterns/onboarding.md +700 -0
- package/expertise/design/patterns/search-and-filter.md +601 -0
- package/expertise/design/patterns/settings-and-preferences.md +768 -0
- package/expertise/design/patterns/social-and-community.md +748 -0
- package/expertise/design/platforms/desktop-native.md +612 -0
- package/expertise/design/platforms/index.md +25 -0
- package/expertise/design/platforms/mobile-android.md +825 -0
- package/expertise/design/platforms/mobile-cross-platform.md +983 -0
- package/expertise/design/platforms/mobile-ios.md +699 -0
- package/expertise/design/platforms/tablet.md +794 -0
- package/expertise/design/platforms/web-dashboard.md +790 -0
- package/expertise/design/platforms/web-responsive.md +550 -0
- package/expertise/design/psychology/behavioral-nudges.md +449 -0
- package/expertise/design/psychology/cognitive-load.md +1191 -0
- package/expertise/design/psychology/error-psychology.md +778 -0
- package/expertise/design/psychology/index.md +22 -0
- package/expertise/design/psychology/persuasive-design.md +736 -0
- package/expertise/design/psychology/user-mental-models.md +623 -0
- package/expertise/design/tooling/open-pencil.md +266 -0
- package/expertise/frontend/angular.md +1073 -0
- package/expertise/frontend/desktop-electron.md +546 -0
- package/expertise/frontend/flutter.md +782 -0
- package/expertise/frontend/index.md +27 -0
- package/expertise/frontend/native-android.md +409 -0
- package/expertise/frontend/native-ios.md +490 -0
- package/expertise/frontend/react-native.md +1160 -0
- package/expertise/frontend/react.md +808 -0
- package/expertise/frontend/vue.md +1089 -0
- package/expertise/humanize/domain-rules-code.md +79 -0
- package/expertise/humanize/domain-rules-content.md +67 -0
- package/expertise/humanize/domain-rules-technical-docs.md +56 -0
- package/expertise/humanize/index.md +35 -0
- package/expertise/humanize/self-audit-checklist.md +87 -0
- package/expertise/humanize/sentence-patterns.md +218 -0
- package/expertise/humanize/vocabulary-blacklist.md +105 -0
- package/expertise/i18n/PROGRESS.md +65 -0
- package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
- package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
- package/expertise/i18n/advanced/complex-scripts.md +30 -0
- package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
- package/expertise/i18n/advanced/testing-i18n.md +28 -0
- package/expertise/i18n/content/content-adaptation.md +23 -0
- package/expertise/i18n/content/locale-specific-formatting.md +23 -0
- package/expertise/i18n/content/machine-translation-integration.md +28 -0
- package/expertise/i18n/content/translation-management.md +29 -0
- package/expertise/i18n/foundations/date-time-calendars.md +67 -0
- package/expertise/i18n/foundations/i18n-architecture.md +272 -0
- package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
- package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
- package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
- package/expertise/i18n/foundations/string-externalization.md +236 -0
- package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
- package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
- package/expertise/i18n/index.md +38 -0
- package/expertise/i18n/platform/backend-i18n.md +31 -0
- package/expertise/i18n/platform/flutter-i18n.md +148 -0
- package/expertise/i18n/platform/native-android-i18n.md +36 -0
- package/expertise/i18n/platform/native-ios-i18n.md +36 -0
- package/expertise/i18n/platform/react-i18n.md +103 -0
- package/expertise/i18n/platform/web-css-i18n.md +81 -0
- package/expertise/i18n/rtl/arabic-specific.md +175 -0
- package/expertise/i18n/rtl/hebrew-specific.md +149 -0
- package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
- package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
- package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
- package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
- package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
- package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
- package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
- package/expertise/i18n/rtl/rtl-typography.md +160 -0
- package/expertise/index.md +113 -0
- package/expertise/index.yaml +216 -0
- package/expertise/infrastructure/cloud-aws.md +597 -0
- package/expertise/infrastructure/cloud-gcp.md +599 -0
- package/expertise/infrastructure/cybersecurity.md +816 -0
- package/expertise/infrastructure/database-mongodb.md +447 -0
- package/expertise/infrastructure/database-postgres.md +400 -0
- package/expertise/infrastructure/devops-cicd.md +787 -0
- package/expertise/infrastructure/index.md +27 -0
- package/expertise/performance/PROGRESS.md +50 -0
- package/expertise/performance/backend/api-latency.md +1204 -0
- package/expertise/performance/backend/background-jobs.md +506 -0
- package/expertise/performance/backend/connection-pooling.md +1209 -0
- package/expertise/performance/backend/database-query-optimization.md +515 -0
- package/expertise/performance/backend/index.md +23 -0
- package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
- package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
- package/expertise/performance/foundations/caching-strategies.md +489 -0
- package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
- package/expertise/performance/foundations/index.md +24 -0
- package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
- package/expertise/performance/foundations/memory-management.md +964 -0
- package/expertise/performance/foundations/performance-budgets.md +1314 -0
- package/expertise/performance/index.md +31 -0
- package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
- package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
- package/expertise/performance/infrastructure/index.md +22 -0
- package/expertise/performance/infrastructure/load-balancing.md +1081 -0
- package/expertise/performance/infrastructure/observability.md +1079 -0
- package/expertise/performance/mobile/index.md +23 -0
- package/expertise/performance/mobile/mobile-animations.md +544 -0
- package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
- package/expertise/performance/mobile/mobile-network.md +452 -0
- package/expertise/performance/mobile/mobile-rendering.md +599 -0
- package/expertise/performance/mobile/mobile-startup-time.md +505 -0
- package/expertise/performance/platform-specific/flutter-performance.md +647 -0
- package/expertise/performance/platform-specific/index.md +22 -0
- package/expertise/performance/platform-specific/node-performance.md +1307 -0
- package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
- package/expertise/performance/platform-specific/react-performance.md +1403 -0
- package/expertise/performance/web/bundle-optimization.md +1239 -0
- package/expertise/performance/web/image-and-media.md +636 -0
- package/expertise/performance/web/index.md +24 -0
- package/expertise/performance/web/network-optimization.md +1133 -0
- package/expertise/performance/web/rendering-performance.md +1098 -0
- package/expertise/performance/web/ssr-and-hydration.md +918 -0
- package/expertise/performance/web/web-vitals.md +1374 -0
- package/expertise/quality/accessibility.md +985 -0
- package/expertise/quality/evidence-based-verification.md +499 -0
- package/expertise/quality/index.md +24 -0
- package/expertise/quality/ml-model-audit.md +614 -0
- package/expertise/quality/performance.md +600 -0
- package/expertise/quality/testing-api.md +891 -0
- package/expertise/quality/testing-mobile.md +496 -0
- package/expertise/quality/testing-web.md +849 -0
- package/expertise/security/PROGRESS.md +54 -0
- package/expertise/security/agentic-identity.md +540 -0
- package/expertise/security/compliance-frameworks.md +601 -0
- package/expertise/security/data/data-encryption.md +364 -0
- package/expertise/security/data/data-privacy-gdpr.md +692 -0
- package/expertise/security/data/database-security.md +1171 -0
- package/expertise/security/data/index.md +22 -0
- package/expertise/security/data/pii-handling.md +531 -0
- package/expertise/security/foundations/authentication.md +1041 -0
- package/expertise/security/foundations/authorization.md +603 -0
- package/expertise/security/foundations/cryptography.md +1001 -0
- package/expertise/security/foundations/index.md +25 -0
- package/expertise/security/foundations/owasp-top-10.md +1354 -0
- package/expertise/security/foundations/secrets-management.md +1217 -0
- package/expertise/security/foundations/secure-sdlc.md +700 -0
- package/expertise/security/foundations/supply-chain-security.md +698 -0
- package/expertise/security/index.md +31 -0
- package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
- package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
- package/expertise/security/infrastructure/container-security.md +721 -0
- package/expertise/security/infrastructure/incident-response.md +1295 -0
- package/expertise/security/infrastructure/index.md +24 -0
- package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
- package/expertise/security/infrastructure/network-security.md +1337 -0
- package/expertise/security/mobile/index.md +23 -0
- package/expertise/security/mobile/mobile-android-security.md +1218 -0
- package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
- package/expertise/security/mobile/mobile-data-storage.md +1265 -0
- package/expertise/security/mobile/mobile-ios-security.md +1401 -0
- package/expertise/security/mobile/mobile-network-security.md +1520 -0
- package/expertise/security/smart-contract-security.md +594 -0
- package/expertise/security/testing/index.md +22 -0
- package/expertise/security/testing/penetration-testing.md +1258 -0
- package/expertise/security/testing/security-code-review.md +1765 -0
- package/expertise/security/testing/threat-modeling.md +1074 -0
- package/expertise/security/testing/vulnerability-scanning.md +1062 -0
- package/expertise/security/web/api-security.md +586 -0
- package/expertise/security/web/cors-and-headers.md +433 -0
- package/expertise/security/web/csrf.md +562 -0
- package/expertise/security/web/file-upload.md +1477 -0
- package/expertise/security/web/index.md +25 -0
- package/expertise/security/web/injection.md +1375 -0
- package/expertise/security/web/session-management.md +1101 -0
- package/expertise/security/web/xss.md +1158 -0
- package/exports/README.md +17 -0
- package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
- package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
- package/exports/hosts/claude/.claude/agents/designer.md +55 -0
- package/exports/hosts/claude/.claude/agents/executor.md +55 -0
- package/exports/hosts/claude/.claude/agents/learner.md +51 -0
- package/exports/hosts/claude/.claude/agents/planner.md +53 -0
- package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
- package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
- package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
- package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
- package/exports/hosts/claude/.claude/commands/author.md +42 -0
- package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
- package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
- package/exports/hosts/claude/.claude/commands/design.md +44 -0
- package/exports/hosts/claude/.claude/commands/discover.md +37 -0
- package/exports/hosts/claude/.claude/commands/execute.md +48 -0
- package/exports/hosts/claude/.claude/commands/learn.md +38 -0
- package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
- package/exports/hosts/claude/.claude/commands/plan.md +39 -0
- package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
- package/exports/hosts/claude/.claude/commands/review.md +40 -0
- package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
- package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
- package/exports/hosts/claude/.claude/commands/specify.md +38 -0
- package/exports/hosts/claude/.claude/commands/verify.md +37 -0
- package/exports/hosts/claude/.claude/settings.json +34 -0
- package/exports/hosts/claude/CLAUDE.md +19 -0
- package/exports/hosts/claude/export.manifest.json +38 -0
- package/exports/hosts/claude/host-package.json +67 -0
- package/exports/hosts/codex/AGENTS.md +19 -0
- package/exports/hosts/codex/export.manifest.json +38 -0
- package/exports/hosts/codex/host-package.json +41 -0
- package/exports/hosts/cursor/.cursor/hooks.json +16 -0
- package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
- package/exports/hosts/cursor/export.manifest.json +38 -0
- package/exports/hosts/cursor/host-package.json +42 -0
- package/exports/hosts/gemini/GEMINI.md +19 -0
- package/exports/hosts/gemini/export.manifest.json +38 -0
- package/exports/hosts/gemini/host-package.json +41 -0
- package/hooks/README.md +18 -0
- package/hooks/definitions/loop_cap_guard.yaml +21 -0
- package/hooks/definitions/post_tool_capture.yaml +24 -0
- package/hooks/definitions/pre_compact_summary.yaml +19 -0
- package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
- package/hooks/definitions/protected_path_write_guard.yaml +19 -0
- package/hooks/definitions/session_start.yaml +19 -0
- package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
- package/hooks/loop-cap-guard +17 -0
- package/hooks/post-tool-lint +36 -0
- package/hooks/protected-path-write-guard +17 -0
- package/hooks/session-start +41 -0
- package/llms-full.txt +2355 -0
- package/llms.txt +43 -0
- package/package.json +79 -0
- package/roles/README.md +20 -0
- package/roles/clarifier.md +42 -0
- package/roles/content-author.md +63 -0
- package/roles/designer.md +55 -0
- package/roles/executor.md +55 -0
- package/roles/learner.md +51 -0
- package/roles/planner.md +53 -0
- package/roles/researcher.md +43 -0
- package/roles/reviewer.md +54 -0
- package/roles/specifier.md +47 -0
- package/roles/verifier.md +71 -0
- package/schemas/README.md +24 -0
- package/schemas/accepted-learning.schema.json +20 -0
- package/schemas/author-artifact.schema.json +156 -0
- package/schemas/clarification.schema.json +19 -0
- package/schemas/design-artifact.schema.json +80 -0
- package/schemas/docs-claim.schema.json +18 -0
- package/schemas/export-manifest.schema.json +20 -0
- package/schemas/hook.schema.json +67 -0
- package/schemas/host-export-package.schema.json +18 -0
- package/schemas/implementation-plan.schema.json +19 -0
- package/schemas/proposed-learning.schema.json +19 -0
- package/schemas/research.schema.json +18 -0
- package/schemas/review.schema.json +29 -0
- package/schemas/run-manifest.schema.json +18 -0
- package/schemas/spec-challenge.schema.json +18 -0
- package/schemas/spec.schema.json +20 -0
- package/schemas/usage.schema.json +102 -0
- package/schemas/verification-proof.schema.json +29 -0
- package/schemas/wazir-manifest.schema.json +173 -0
- package/skills/README.md +40 -0
- package/skills/brainstorming/SKILL.md +77 -0
- package/skills/debugging/SKILL.md +50 -0
- package/skills/design/SKILL.md +61 -0
- package/skills/dispatching-parallel-agents/SKILL.md +128 -0
- package/skills/executing-plans/SKILL.md +70 -0
- package/skills/finishing-a-development-branch/SKILL.md +169 -0
- package/skills/humanize/SKILL.md +123 -0
- package/skills/init-pipeline/SKILL.md +124 -0
- package/skills/prepare-next/SKILL.md +20 -0
- package/skills/receiving-code-review/SKILL.md +123 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +108 -0
- package/skills/run-audit/SKILL.md +197 -0
- package/skills/scan-project/SKILL.md +41 -0
- package/skills/self-audit/SKILL.md +153 -0
- package/skills/subagent-driven-development/SKILL.md +154 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/skills/subagent-driven-development/implementer-prompt.md +102 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/tdd/SKILL.md +23 -0
- package/skills/using-git-worktrees/SKILL.md +163 -0
- package/skills/using-skills/SKILL.md +95 -0
- package/skills/verification/SKILL.md +22 -0
- package/skills/wazir/SKILL.md +463 -0
- package/skills/writing-plans/SKILL.md +30 -0
- package/skills/writing-skills/SKILL.md +157 -0
- package/skills/writing-skills/anthropic-best-practices.md +122 -0
- package/skills/writing-skills/persuasion-principles.md +50 -0
- package/templates/README.md +20 -0
- package/templates/artifacts/README.md +10 -0
- package/templates/artifacts/accepted-learning.md +19 -0
- package/templates/artifacts/accepted-learning.template.json +12 -0
- package/templates/artifacts/author.md +74 -0
- package/templates/artifacts/author.template.json +19 -0
- package/templates/artifacts/clarification.md +21 -0
- package/templates/artifacts/clarification.template.json +12 -0
- package/templates/artifacts/execute-notes.md +19 -0
- package/templates/artifacts/implementation-plan.md +21 -0
- package/templates/artifacts/implementation-plan.template.json +11 -0
- package/templates/artifacts/learning-proposal.md +19 -0
- package/templates/artifacts/next-run-handoff.md +21 -0
- package/templates/artifacts/plan-review.md +19 -0
- package/templates/artifacts/proposed-learning.template.json +12 -0
- package/templates/artifacts/research.md +21 -0
- package/templates/artifacts/research.template.json +12 -0
- package/templates/artifacts/review-findings.md +19 -0
- package/templates/artifacts/review.template.json +11 -0
- package/templates/artifacts/run-manifest.template.json +8 -0
- package/templates/artifacts/spec-challenge.md +19 -0
- package/templates/artifacts/spec-challenge.template.json +11 -0
- package/templates/artifacts/spec.md +21 -0
- package/templates/artifacts/spec.template.json +12 -0
- package/templates/artifacts/verification-proof.md +19 -0
- package/templates/artifacts/verification-proof.template.json +11 -0
- package/templates/examples/accepted-learning.example.json +14 -0
- package/templates/examples/author.example.json +152 -0
- package/templates/examples/clarification.example.json +15 -0
- package/templates/examples/docs-claim.example.json +8 -0
- package/templates/examples/export-manifest.example.json +7 -0
- package/templates/examples/host-export-package.example.json +11 -0
- package/templates/examples/implementation-plan.example.json +17 -0
- package/templates/examples/proposed-learning.example.json +13 -0
- package/templates/examples/research.example.json +15 -0
- package/templates/examples/research.example.md +6 -0
- package/templates/examples/review.example.json +17 -0
- package/templates/examples/run-manifest.example.json +9 -0
- package/templates/examples/spec-challenge.example.json +14 -0
- package/templates/examples/spec.example.json +21 -0
- package/templates/examples/verification-proof.example.json +21 -0
- package/templates/examples/wazir-manifest.example.yaml +65 -0
- package/templates/task-definition-schema.md +99 -0
- package/tooling/README.md +20 -0
- package/tooling/src/adapters/context-mode.js +50 -0
- package/tooling/src/capture/command.js +376 -0
- package/tooling/src/capture/store.js +99 -0
- package/tooling/src/capture/usage.js +270 -0
- package/tooling/src/checks/branches.js +50 -0
- package/tooling/src/checks/brand-truth.js +110 -0
- package/tooling/src/checks/changelog.js +231 -0
- package/tooling/src/checks/command-registry.js +36 -0
- package/tooling/src/checks/commits.js +102 -0
- package/tooling/src/checks/docs-drift.js +103 -0
- package/tooling/src/checks/docs-truth.js +201 -0
- package/tooling/src/checks/runtime-surface.js +156 -0
- package/tooling/src/cli.js +116 -0
- package/tooling/src/command-options.js +56 -0
- package/tooling/src/commands/validate.js +320 -0
- package/tooling/src/doctor/command.js +91 -0
- package/tooling/src/export/command.js +77 -0
- package/tooling/src/export/compiler.js +498 -0
- package/tooling/src/guards/loop-cap-guard.js +52 -0
- package/tooling/src/guards/protected-path-write-guard.js +67 -0
- package/tooling/src/index/command.js +152 -0
- package/tooling/src/index/storage.js +1061 -0
- package/tooling/src/index/summarizers.js +261 -0
- package/tooling/src/loaders.js +18 -0
- package/tooling/src/project-root.js +22 -0
- package/tooling/src/recall/command.js +225 -0
- package/tooling/src/schema-validator.js +30 -0
- package/tooling/src/state-root.js +40 -0
- package/tooling/src/status/command.js +71 -0
- package/wazir.manifest.yaml +135 -0
- package/workflows/README.md +19 -0
- package/workflows/author.md +42 -0
- package/workflows/clarify.md +38 -0
- package/workflows/design-review.md +46 -0
- package/workflows/design.md +44 -0
- package/workflows/discover.md +37 -0
- package/workflows/execute.md +48 -0
- package/workflows/learn.md +38 -0
- package/workflows/plan-review.md +42 -0
- package/workflows/plan.md +39 -0
- package/workflows/prepare-next.md +37 -0
- package/workflows/review.md +40 -0
- package/workflows/run-audit.md +41 -0
- package/workflows/spec-challenge.md +41 -0
- package/workflows/specify.md +38 -0
- package/workflows/verify.md +37 -0
|
@@ -0,0 +1,638 @@
|
|
|
1
|
+
# API Design — GraphQL — Architecture Expertise Module
|
|
2
|
+
|
|
3
|
+
> GraphQL is a query language for APIs that lets clients request exactly the data they need. It solves REST's over-fetching/under-fetching problems but introduces significant complexity in caching, authorization, performance, and N+1 queries. Best for client-heavy applications with complex, nested data requirements.
|
|
4
|
+
|
|
5
|
+
> **Category:** Integration
|
|
6
|
+
> **Complexity:** Complex
|
|
7
|
+
> **Applies when:** Applications with complex, deeply nested data requirements where multiple client types need different data shapes from the same API
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What This Is (and What It Isn't)
|
|
12
|
+
|
|
13
|
+
### The Core Idea
|
|
14
|
+
|
|
15
|
+
GraphQL is a **query language and runtime** for APIs, created at Facebook in 2012 and open-sourced in 2015. The fundamental premise: the client describes the shape of the data it needs, and the server returns exactly that shape. No more, no less.
|
|
16
|
+
|
|
17
|
+
In a REST API, the server decides what data each endpoint returns. The client gets a fixed payload and either receives too much (over-fetching) or needs to make additional requests to fill gaps (under-fetching). GraphQL inverts this: the server publishes a schema of everything that is queryable, and the client composes a query specifying the exact fields, relationships, and nesting depth it requires.
|
|
18
|
+
|
|
19
|
+
```graphql
|
|
20
|
+
query { # Response mirrors query shape exactly:
|
|
21
|
+
user(id: "123") { # { "data": { "user": {
|
|
22
|
+
name # "name": "Jane Doe",
|
|
23
|
+
email # "email": "jane@example.com",
|
|
24
|
+
posts(first: 5) { # "posts": [
|
|
25
|
+
title # { "title": "GraphQL in Practice",
|
|
26
|
+
commentCount # "commentCount": 42 }, ...
|
|
27
|
+
} # ]
|
|
28
|
+
} # }}}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
With REST, this would require `GET /users/123` + `GET /users/123/posts?limit=5` + possibly comment counts per post — three round trips, each returning fields the client does not need.
|
|
33
|
+
|
|
34
|
+
### The Three Operations
|
|
35
|
+
|
|
36
|
+
**Queries** read data. They are analogous to GET requests but can traverse multiple resources in a single call.
|
|
37
|
+
|
|
38
|
+
**Mutations** write data. They are analogous to POST/PUT/DELETE but follow a different contract: the client specifies what to write and what to return from the result. A mutation to create a user can return the created user's ID, name, and computed fields in one round trip.
|
|
39
|
+
|
|
40
|
+
**Subscriptions** stream real-time updates. The client subscribes to a specific event, and the server pushes data when it changes. Built on WebSockets or Server-Sent Events. This is the least mature of the three operations and carries its own operational complexity.
|
|
41
|
+
|
|
42
|
+
### Schema-First Design
|
|
43
|
+
|
|
44
|
+
GraphQL is schema-first. The schema is a contract written in the Schema Definition Language (SDL):
|
|
45
|
+
|
|
46
|
+
```graphql
|
|
47
|
+
type User {
|
|
48
|
+
id: ID!
|
|
49
|
+
name: String!
|
|
50
|
+
email: String!
|
|
51
|
+
posts(first: Int, after: String): PostConnection!
|
|
52
|
+
role: Role!
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
enum Role { ADMIN EDITOR VIEWER }
|
|
56
|
+
|
|
57
|
+
type Post { id: ID! title: String! body: String! author: User! comments: [Comment!]! createdAt: DateTime! }
|
|
58
|
+
|
|
59
|
+
type Query { user(id: ID!): User users(first: Int, after: String): UserConnection! }
|
|
60
|
+
type Mutation { createPost(input: CreatePostInput!): CreatePostPayload! }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The schema is both documentation and enforcement. The type system catches malformed queries before execution. Tooling (GraphQL Code Generator) produces client-side types from the schema, eliminating a class of runtime errors. Design schemas for client needs, not database tables. Use `!` (non-null) deliberately. Return payload types from mutations to include structured user errors.
|
|
64
|
+
|
|
65
|
+
### Resolvers: Where the Work Happens
|
|
66
|
+
|
|
67
|
+
Every field in the schema has a **resolver** — a function that returns the value for that field. The runtime walks the query tree depth-first, calling resolvers at each node. Each resolver is independent — the runtime composes them based on the query. This is elegant for modularity but creates the N+1 problem (covered in Failure Modes).
|
|
68
|
+
|
|
69
|
+
### What GraphQL Is NOT
|
|
70
|
+
|
|
71
|
+
**Not a database query language.** Despite the name, GraphQL does not query databases. It queries an API layer. Behind the resolvers can be databases, microservices, REST APIs, files, or any data source. The "QL" is a query language for the API, not for storage.
|
|
72
|
+
|
|
73
|
+
**Not "better REST."** GraphQL is a different paradigm with different trade-offs. REST has mature caching (HTTP cache headers, CDN support, ETag-based invalidation), standardized error codes (4xx/5xx), and universal tooling. GraphQL trades these for query flexibility and type safety. Calling GraphQL "better REST" mischaracterizes both.
|
|
74
|
+
|
|
75
|
+
**Not a transport protocol.** GraphQL is typically served over HTTP (usually POST to a single endpoint), but the spec is transport-agnostic. It defines a query language and execution semantics, not how the bytes move.
|
|
76
|
+
|
|
77
|
+
**Not automatically faster.** A single GraphQL query can be more efficient than multiple REST calls, but a poorly designed schema with unoptimized resolvers can be dramatically slower than a well-designed REST API. Performance depends on implementation, not paradigm.
|
|
78
|
+
|
|
79
|
+
**Not a replacement for API design.** You still need to design your schema carefully. A schema that exposes raw database tables is as poorly designed as a REST API that maps 1:1 to database rows. Domain modeling matters regardless of the API paradigm.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## When to Use It
|
|
84
|
+
|
|
85
|
+
### The Qualifying Conditions
|
|
86
|
+
|
|
87
|
+
Apply GraphQL when **two or more** of these conditions hold:
|
|
88
|
+
|
|
89
|
+
**Multiple client types with divergent data needs.** A web dashboard needs 15 fields from a user profile. A mobile app needs 5. A watch app needs 2. With REST, you either return all 15 fields to everyone (over-fetching, wasting mobile bandwidth) or maintain three separate endpoints (maintenance burden). GraphQL lets each client request exactly what it needs from a single schema. This was Facebook's original motivation: the desktop news feed, mobile app, and embedded widgets all needed different slices of the same data graph.
|
|
90
|
+
|
|
91
|
+
**Deeply nested, relational data.** When a single screen needs data that spans 3+ entity relationships (user -> posts -> comments -> author -> avatar), REST requires either multiple round trips or specialized aggregate endpoints that tightly couple the API to a specific UI view. GraphQL's nested query structure maps naturally to relational data traversal.
|
|
92
|
+
|
|
93
|
+
**Rapid frontend iteration.** When frontend teams ship new features weekly and each feature needs a different data shape, REST creates a bottleneck: every new data requirement becomes a backend ticket to create or modify an endpoint. With GraphQL, frontend developers can query any combination of fields and relationships that the schema already exposes, without waiting for backend changes. This decouples frontend and backend release cycles.
|
|
94
|
+
|
|
95
|
+
**Strong typing and developer experience are priorities.** GraphQL's schema doubles as documentation and enables powerful tooling: auto-complete in IDEs, compile-time type checking (with codegen tools like GraphQL Code Generator), and schema-aware linting. For teams that value type safety across the full stack, GraphQL provides this from the API layer outward.
|
|
96
|
+
|
|
97
|
+
**API evolution without versioning.** REST APIs often use URL versioning (`/v1/users`, `/v2/users`) when fields need to change. GraphQL handles evolution through schema deprecation: mark a field as `@deprecated(reason: "Use fullName instead")`, clients update on their own schedule, and the field is eventually removed. No URL changes, no version maintenance.
|
|
98
|
+
|
|
99
|
+
### Real-World Contexts Where This Pays Off
|
|
100
|
+
|
|
101
|
+
**GitHub API v4.** GitHub migrated from REST (v3) to GraphQL (v4) specifically because their API consumers needed wildly different data shapes. A CI tool needs commit SHAs and statuses. A project management tool needs issues, labels, and assignees. A code review tool needs pull request diffs and comments. Rather than maintaining hundreds of REST endpoints with `?fields=` query parameters, GraphQL lets each integration request exactly what it needs. GitHub reported that GraphQL reduced the number of API calls and total data transferred for most use cases — retrieving a repository's issues, labels, assignees, and comments in a single query instead of several nested REST calls.
|
|
102
|
+
|
|
103
|
+
**Shopify Storefront API.** Shopify's Storefront API uses GraphQL because e-commerce storefronts have extreme variance in data requirements. A headless storefront showing product cards needs title, price, and thumbnail. A product detail page needs full descriptions, variant options, metafields, and inventory. A checkout flow needs cart state, discount calculations, and shipping rates. GraphQL lets each storefront component request its exact data needs. Shopify assigns query cost scores to fields and enforces rate limits based on total query cost rather than request count.
|
|
104
|
+
|
|
105
|
+
**Facebook (origin).** Facebook created GraphQL in 2012 to solve a specific problem: the Facebook mobile app needed to render complex, nested news feed stories with varying data shapes (text posts, photos, videos, link previews, shared posts) and the REST API could not serve these efficiently. The mobile app was sending dozens of REST requests per feed render. GraphQL reduced this to a single query per feed load with exactly the fields each story type needed.
|
|
106
|
+
|
|
107
|
+
**Airbnb.** Airbnb adopted GraphQL to unify data fetching across web and native mobile apps. Their listing pages combine data from dozens of backend services (pricing, availability, reviews, host profiles, amenities, photos). GraphQL's resolver architecture let them compose this data from multiple microservices behind a single schema without creating monolithic aggregate endpoints.
|
|
108
|
+
|
|
109
|
+
**Twitter (X) API v2.** Twitter's API v2 adopted GraphQL-like field selection (`?tweet.fields=text,created_at&expansions=author_id`) because their API consumers had the same over-fetching problem. While not pure GraphQL, the adoption of its core concept (client-specified fields) validates the pattern.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## When NOT to Use It
|
|
114
|
+
|
|
115
|
+
This section is deliberately as long as the "When to Use It" section. GraphQL is frequently adopted because it is trendy, without evaluating whether the complexity it introduces is earned by the problems it solves. The teams that abandon GraphQL almost always cite one or more of these conditions.
|
|
116
|
+
|
|
117
|
+
### The Disqualifying Conditions
|
|
118
|
+
|
|
119
|
+
**Simple CRUD APIs with few consumers.** If you have one frontend, one backend, and the data model is flat (users, products, orders with straightforward relationships), REST gives you everything you need with dramatically less complexity. A `GET /users/123` returning a fixed payload is simpler to build, test, cache, and monitor than a GraphQL query for the same data. The resolver infrastructure, schema definition, DataLoader setup, and query cost analysis all represent overhead that provides no return when the data needs are simple and uniform.
|
|
120
|
+
|
|
121
|
+
**File uploads and binary data.** GraphQL is designed for structured, JSON-serializable data. File uploads require workarounds: multipart form data extensions (the `graphql-upload` spec), pre-signed URL flows, or hybrid approaches where uploads go through a REST endpoint and the resulting URL is passed to a GraphQL mutation. None of these are clean. If file handling is a primary concern, REST or dedicated upload services are simpler.
|
|
122
|
+
|
|
123
|
+
**Real-time streaming of high-volume data.** GraphQL subscriptions work for moderate real-time needs (chat messages, notification badges), but high-volume streaming (financial market data, IoT sensor feeds, live video metadata) pushes subscriptions beyond their design point. WebSockets, Server-Sent Events, or gRPC streaming handle these cases with less overhead. The subscription resolver model adds per-field resolution cost to every pushed event.
|
|
124
|
+
|
|
125
|
+
**Public APIs with untrusted consumers.** When you expose an API to unknown third parties, GraphQL's flexibility becomes a liability. Clients can craft arbitrarily expensive queries: deeply nested, broadly fanned out, with aliases that multiply resolution cost. You must implement query cost analysis, depth limiting, breadth limiting, persisted queries, and rate limiting to prevent abuse. REST's fixed endpoints have a predictable cost per request that is trivially rate-limited. The OWASP GraphQL Cheat Sheet identifies introspection exposure, query cost attacks, batching abuse, and field-level authorization bypass as primary security concerns for public GraphQL APIs.
|
|
126
|
+
|
|
127
|
+
**Teams without GraphQL expertise.** GraphQL has a genuine learning curve. The schema type system, resolver architecture, DataLoader batching, fragment composition, cursor-based pagination, error handling conventions, and caching strategies are all concepts that do not exist in REST. A team of four developers who have never used GraphQL will spend 2-4 weeks becoming productive and 2-3 months before they can operate the system confidently in production. If the project timeline does not accommodate this, REST is the pragmatic choice.
|
|
128
|
+
|
|
129
|
+
**Caching is a critical performance requirement.** REST APIs benefit from decades of HTTP caching infrastructure: CDNs cache GET responses by URL, browsers cache with ETags and Cache-Control headers, reverse proxies (Varnish, Nginx) cache at the edge. GraphQL sends POST requests to a single endpoint with the query in the body. HTTP caching infrastructure cannot cache these by default. You must implement application-level caching: normalized client caches (Apollo Client's InMemoryCache), persisted query hashing for CDN caching, or custom server-side cache layers keyed by query hash. This is solvable but represents significant engineering effort that REST gets for free.
|
|
130
|
+
|
|
131
|
+
**N+1 query patterns are not manageable.** Every nested relationship in a GraphQL query triggers resolver calls that can produce N+1 database queries. The standard solution is DataLoader, but DataLoader requires disciplined implementation: one loader per data type, request-scoped instances, correct key ordering, and careful batch function design. If your data access layer does not support batching (some legacy ORMs, external APIs with no batch endpoints), DataLoader cannot help, and your GraphQL API will be slower than the REST API it replaces.
|
|
132
|
+
|
|
133
|
+
**Authorization logic is field-level.** In REST, authorization is typically per-endpoint: can this user access `GET /admin/reports`? In GraphQL, every field in the schema is independently queryable, so authorization must be per-field: can this user see `user.email`? Can this user see `user.salary`? Can this user see `post.moderationNotes`? This requires a field-level authorization layer that runs on every resolver. Frameworks like `graphql-shield` exist, but the mental model shift from "protect endpoints" to "protect every field" catches teams off guard and produces authorization gaps.
|
|
134
|
+
|
|
135
|
+
### Real-World Departures
|
|
136
|
+
|
|
137
|
+
Multiple teams have publicly documented their moves away from GraphQL:
|
|
138
|
+
|
|
139
|
+
**Complexity without proportional benefit.** A recurring pattern: teams adopt GraphQL for a system with 10-15 entity types and a single frontend. The schema, resolvers, DataLoader instances, type definitions, and codegen pipeline add significant boilerplate for what amounts to a CRUD API. After 6-12 months, the team realizes they are maintaining GraphQL infrastructure that provides no benefit over REST because they have only one client and the data shapes never vary.
|
|
140
|
+
|
|
141
|
+
**Debugging pain.** GraphQL returns HTTP 200 for everything. Errors are embedded in the response body as a structured `errors` array. This breaks conventional monitoring that relies on HTTP status codes. A malformed query, a missing required argument, an authorization failure, and a server crash all return 200 OK. Teams must build custom error extraction and alerting on top of the standard response format, and existing API monitoring tools (Datadog, New Relic, PagerDuty) require custom instrumentation to distinguish GraphQL errors from successes.
|
|
142
|
+
|
|
143
|
+
**Tooling gaps.** While GraphQL tooling has matured significantly, it still lags behind REST in some areas. Load testing tools, API gateways, rate limiters, and monitoring dashboards often have first-class REST support and bolted-on GraphQL support. Teams at scale report spending significant time building custom tooling for query analysis, cost tracking, and performance profiling that REST teams get from off-the-shelf solutions.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## How It Works
|
|
148
|
+
|
|
149
|
+
### Schema Definition
|
|
150
|
+
|
|
151
|
+
The schema is the contract between client and server, written in SDL. Key constructs beyond basic types:
|
|
152
|
+
|
|
153
|
+
```graphql
|
|
154
|
+
scalar DateTime # Custom scalars for domain types
|
|
155
|
+
input CreatePostInput { title: String! body: String! tags: [String!] } # Input types for mutations
|
|
156
|
+
type CreatePostPayload { post: Post errors: [UserError!]! } # Payload types with errors
|
|
157
|
+
type UserError { field: String! message: String! }
|
|
158
|
+
interface Node { id: ID! } # Interface for global object identification
|
|
159
|
+
union SearchResult = User | Post | Comment # Union for polymorphic results
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Queries, Mutations, and Subscriptions
|
|
163
|
+
|
|
164
|
+
**Queries** — read operations with nested field selection. A single query can traverse multiple entities, use inline fragments for polymorphic types, and include pagination:
|
|
165
|
+
|
|
166
|
+
```graphql
|
|
167
|
+
query GetUserDashboard($userId: ID!) {
|
|
168
|
+
user(id: $userId) {
|
|
169
|
+
name
|
|
170
|
+
avatar { url(size: MEDIUM) }
|
|
171
|
+
recentPosts(first: 10) {
|
|
172
|
+
edges { node { title publishedAt stats { viewCount commentCount } } }
|
|
173
|
+
pageInfo { hasNextPage endCursor }
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Mutations** — write operations that return affected data and structured errors in one round trip:
|
|
180
|
+
|
|
181
|
+
```graphql
|
|
182
|
+
mutation CreatePost($input: CreatePostInput!) {
|
|
183
|
+
createPost(input: $input) {
|
|
184
|
+
post { id title slug publishedAt }
|
|
185
|
+
errors { field message }
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Subscriptions** — real-time event streams over WebSockets. Least mature of the three; carries operational complexity for high-volume use cases:
|
|
191
|
+
|
|
192
|
+
```graphql
|
|
193
|
+
subscription OnNewComment($postId: ID!) {
|
|
194
|
+
commentAdded(postId: $postId) { id body author { name } createdAt }
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Resolvers and Execution
|
|
199
|
+
|
|
200
|
+
The GraphQL runtime executes queries by walking the query tree and calling the resolver for each field. Execution happens depth-first: all fields at depth 0 resolve, then depth 1, and so on. Each resolver receives four arguments: `parent` (the resolved parent object), `args` (field arguments), `context` (request-scoped shared state), and `info` (query AST metadata).
|
|
201
|
+
|
|
202
|
+
Key resolver patterns:
|
|
203
|
+
- **Default resolvers** — if no resolver is defined, GraphQL returns `parent[fieldName]` automatically. Only write resolvers for computed fields, related data, or authorization.
|
|
204
|
+
- **Union/interface resolution** — use `__resolveType` to tell the runtime which concrete type an object belongs to.
|
|
205
|
+
- **Computed fields** — resolvers can return derived values: `fullName: (user) => \`${user.firstName} ${user.lastName}\``.
|
|
206
|
+
- **Authorization** — resolvers are the natural place for field-level auth checks, though declarative tools like `graphql-shield` are preferred over inline checks.
|
|
207
|
+
|
|
208
|
+
### DataLoader: Solving the N+1 Problem
|
|
209
|
+
|
|
210
|
+
The N+1 problem is GraphQL's most critical performance issue. When a query requests a list of 100 users and each user's posts, the naive approach issues 1 query for users + 100 queries for posts = 101 database queries for one GraphQL request.
|
|
211
|
+
|
|
212
|
+
**DataLoader** solves this through batching: it collects all `.load(key)` calls within a single tick of the event loop and calls a batch function once with all keys. The batch function issues a single `WHERE id IN (...)` query instead of N individual queries. (See Implementation Sketch for code.)
|
|
213
|
+
|
|
214
|
+
**DataLoader rules:**
|
|
215
|
+
1. **Request-scoped instances.** Create a new DataLoader per request. Sharing across requests leaks cached data between users — an authorization vulnerability.
|
|
216
|
+
2. **Key ordering contract.** The batch function must return results in the same order as the input keys. Missing results must be `null` or empty array, not omitted.
|
|
217
|
+
3. **One loader per access pattern.** `userById` and `userByEmail` are separate DataLoaders. Do not overload a single loader with multiple access patterns.
|
|
218
|
+
4. **Batch size limits.** If the database has parameter limits (PostgreSQL: 65535), configure `maxBatchSize` to stay within bounds.
|
|
219
|
+
|
|
220
|
+
### Fragments and Reuse
|
|
221
|
+
|
|
222
|
+
Fragments define reusable field selections that can be composed across queries:
|
|
223
|
+
|
|
224
|
+
```graphql
|
|
225
|
+
fragment PostPreview on Post {
|
|
226
|
+
id
|
|
227
|
+
title
|
|
228
|
+
excerpt
|
|
229
|
+
publishedAt
|
|
230
|
+
author { id name avatar { url(size: SMALL) } }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
query Feed {
|
|
234
|
+
featuredPosts(first: 3) { ...PostPreview coverImage { url(size: LARGE) } }
|
|
235
|
+
recentPosts(first: 10) { ...PostPreview }
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Fragments are the foundation of Relay's component-level data declaration model: each React component declares a fragment of the data it needs, and the parent query composes them. With codegen, this produces type-safe props that match the fragment exactly.
|
|
240
|
+
|
|
241
|
+
### Pagination: Cursor-Based
|
|
242
|
+
|
|
243
|
+
GraphQL best practice follows the Relay Connection Specification: `PostConnection { edges: [PostEdge!]! pageInfo: PageInfo! }` where each edge has a `node` and `cursor`, and `pageInfo` has `hasNextPage`/`endCursor`. Usage: `posts(first: 10)` for the first page, `posts(first: 10, after: "endCursor")` for subsequent pages.
|
|
244
|
+
|
|
245
|
+
Cursor-based pagination avoids the offset problem (items shifting between pages as data changes) and works efficiently with database index scans. The cursor is typically an opaque, base64-encoded identifier (not a raw database ID).
|
|
246
|
+
|
|
247
|
+
### Error Handling
|
|
248
|
+
|
|
249
|
+
Three error categories: **Request errors** (invalid query syntax, unknown field) are caught before execution and returned in the top-level `errors` array with no `data`. **Field errors** (resolver throws) set the field to `null` if nullable, or propagate to the nearest nullable parent, with the error in `errors` with a `path`. **Application errors** (validation, not-found, permission denied) should be modeled as part of the schema using union return types (`union CreatePostResult = CreatePostSuccess | ValidationError | NotFoundError`) — this makes error states explicit, typed, and exhaustively checkable by the client, rather than buried in an untyped `errors` array.
|
|
250
|
+
|
|
251
|
+
### Schema Stitching and Federation
|
|
252
|
+
|
|
253
|
+
When a GraphQL API spans multiple backend services, two approaches exist for composing schemas:
|
|
254
|
+
|
|
255
|
+
**Schema Stitching** merges multiple GraphQL schemas into one at the gateway level. The gateway understands the full schema and delegates queries to the appropriate backend. This is simpler to start with but creates a monolithic gateway that must be updated whenever any backend schema changes. Stitching requires gateway-level code to link types across services (e.g., linking a `Post.author` field to the User service).
|
|
256
|
+
|
|
257
|
+
**Apollo Federation** (and its open alternatives like GraphQL Mesh, WunderGraph) takes a distributed approach. Each service declares its own schema with federation-specific directives (`@key`, `@external`, `@requires`, `@provides`). A router (Apollo Router, formerly Apollo Gateway) composes these schemas automatically and routes query fragments to the appropriate services.
|
|
258
|
+
|
|
259
|
+
```graphql
|
|
260
|
+
# User service schema (federated)
|
|
261
|
+
type User @key(fields: "id") {
|
|
262
|
+
id: ID!
|
|
263
|
+
name: String!
|
|
264
|
+
email: String!
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
# Post service schema (federated)
|
|
268
|
+
type Post @key(fields: "id") {
|
|
269
|
+
id: ID!
|
|
270
|
+
title: String!
|
|
271
|
+
body: String!
|
|
272
|
+
author: User! # Resolved by the User service via federation
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
extend type User @key(fields: "id") {
|
|
276
|
+
id: ID! @external
|
|
277
|
+
posts: [Post!]! # Posts service adds this field to User
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Expedia's migration** from schema stitching to Apollo Federation is a notable case study: they reported improved gateway processing latency and reduced maintenance burden from eliminating the custom stitching code that linked types across services.
|
|
282
|
+
|
|
283
|
+
Federation is the right choice when: multiple teams independently own parts of the graph, the graph spans 5+ services, and teams need to deploy their schema changes independently. It is overkill when: one team owns the whole graph, fewer than 3 services contribute to the schema, or the team is still learning GraphQL fundamentals.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Trade-Offs Matrix
|
|
288
|
+
|
|
289
|
+
| Dimension | GraphQL | REST | When GraphQL Wins | When REST Wins |
|
|
290
|
+
|---|---|---|---|---|
|
|
291
|
+
| **Data fetching precision** | Client specifies exact fields | Server defines fixed payloads | Multiple clients with different data needs | Single client, uniform data needs |
|
|
292
|
+
| **Number of round trips** | Single query for nested data | Multiple requests for related resources | Deep object graphs (3+ levels) | Flat resources, single entity lookups |
|
|
293
|
+
| **HTTP caching** | Requires custom implementation (query hashing, persisted queries, normalized caches) | Native HTTP caching (CDN, ETags, Cache-Control) | Application-level caching acceptable | Aggressive caching required (public APIs, static content) |
|
|
294
|
+
| **Type safety** | Built-in schema type system, codegen to client types | Requires OpenAPI/Swagger, optional enforcement | Full-stack type safety is a priority | Simple APIs where type safety overhead is not justified |
|
|
295
|
+
| **API evolution** | Field deprecation, additive changes, no versioning | URL versioning or content negotiation | Gradual migration with many consumers | Breaking changes need hard cutover |
|
|
296
|
+
| **Learning curve** | Schema design, resolvers, DataLoader, fragments, subscriptions | HTTP methods, status codes, URL design | Team has GraphQL experience | Team is new to API design |
|
|
297
|
+
| **Payload size** | Minimal — only requested fields returned | Fixed — full resource representation | Mobile apps on constrained networks | Internal services with high bandwidth |
|
|
298
|
+
| **Error handling** | Everything is HTTP 200, errors in response body | HTTP status codes (400, 401, 403, 404, 500) | Partial success is valuable (some fields resolve, others error) | Standard monitoring, alerting, and debugging workflows |
|
|
299
|
+
| **Tooling maturity** | Growing ecosystem, some gaps in monitoring and load testing | Decades of mature tooling (Postman, curl, CDNs, API gateways) | Modern frontend-centric development | Enterprise environments with established REST tooling |
|
|
300
|
+
| **Authorization model** | Per-field authorization required | Per-endpoint authorization | Fine-grained data access control needed | Coarse-grained endpoint-level access sufficient |
|
|
301
|
+
| **Query predictability** | Clients can craft arbitrary queries | Server controls all query patterns | Trusted first-party clients | Public APIs with untrusted consumers |
|
|
302
|
+
| **Real-time support** | Subscriptions (WebSocket-based) | Polling, SSE, or WebSocket (separate from API) | Moderate real-time needs integrated with data fetching | High-volume streaming, dedicated real-time infrastructure |
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Evolution Path
|
|
307
|
+
|
|
308
|
+
### Stage 1: REST-First (start here for most teams)
|
|
309
|
+
|
|
310
|
+
- Traditional REST API with JSON responses.
|
|
311
|
+
- OpenAPI/Swagger for documentation and type generation.
|
|
312
|
+
- HTTP caching with CDN and Cache-Control headers.
|
|
313
|
+
- Standard monitoring with HTTP status codes.
|
|
314
|
+
- Move to Stage 2 when: multiple clients with divergent data needs emerge, or the number of aggregate/composite endpoints grows unmanageably.
|
|
315
|
+
|
|
316
|
+
### Stage 2: GraphQL for Client-Facing, REST for Internal
|
|
317
|
+
|
|
318
|
+
- GraphQL API for frontend clients (web, mobile, third-party integrations).
|
|
319
|
+
- REST APIs remain for service-to-service communication, file uploads, webhooks.
|
|
320
|
+
- DataLoader implemented for all relationship resolvers.
|
|
321
|
+
- Schema codegen generates client types.
|
|
322
|
+
- Query cost analysis and depth limiting in place.
|
|
323
|
+
- Move to Stage 3 when: schema spans 5+ backend services, multiple teams contribute to the graph.
|
|
324
|
+
|
|
325
|
+
### Stage 3: Federated GraphQL
|
|
326
|
+
|
|
327
|
+
- Apollo Federation or equivalent composes schemas from multiple services.
|
|
328
|
+
- Each team owns their subgraph and deploys independently.
|
|
329
|
+
- Router handles query planning and execution across subgraphs.
|
|
330
|
+
- Schema registry tracks schema versions and validates changes for compatibility.
|
|
331
|
+
- Persisted queries for production traffic; introspection disabled.
|
|
332
|
+
- Move to Stage 4 when: performance requirements demand fine-grained optimization, or the graph spans 15+ subgraphs.
|
|
333
|
+
|
|
334
|
+
### Stage 4: Optimized Federation with Edge Caching
|
|
335
|
+
|
|
336
|
+
- Automatic persisted queries (APQ) with CDN edge caching.
|
|
337
|
+
- Query plan caching at the router level.
|
|
338
|
+
- @defer and @stream directives for incremental delivery.
|
|
339
|
+
- Distributed tracing across subgraph resolvers.
|
|
340
|
+
- Custom query cost models tuned to actual resolver performance.
|
|
341
|
+
- Schema linting and review integrated into CI/CD.
|
|
342
|
+
|
|
343
|
+
### Backward Compatibility Strategy
|
|
344
|
+
|
|
345
|
+
At every stage, REST endpoints can coexist with GraphQL. GraphQL does not require abandoning REST. The pragmatic approach: expose new, complex data requirements through GraphQL; keep simple CRUD and internal APIs on REST; never force a migration that does not solve a real problem.
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Failure Modes
|
|
350
|
+
|
|
351
|
+
### 1. N+1 Query Explosion
|
|
352
|
+
|
|
353
|
+
**What happens:** A query requests a list of 50 users, each with their posts, each post with its comments, each comment with its author. Without DataLoader, this generates: 1 query (users) + 50 queries (posts per user) + N queries (comments per post) + M queries (author per comment). A single GraphQL request produces hundreds or thousands of database queries.
|
|
354
|
+
|
|
355
|
+
**Why it happens:** Resolvers are independent functions. The `Post.comments` resolver does not know that 49 other posts also need their comments. Each resolver issues its own query.
|
|
356
|
+
|
|
357
|
+
**How to detect:** Enable query logging in your database. A single HTTP request generating 50+ SQL queries is a clear signal. Apollo Studio and other GraphQL monitoring tools expose per-resolver timing and query counts.
|
|
358
|
+
|
|
359
|
+
**How to prevent:**
|
|
360
|
+
- Use DataLoader for every resolver that fetches related data. No exceptions.
|
|
361
|
+
- Set up monitoring that alerts when a single GraphQL request generates more than N database queries (threshold depends on your schema complexity, but 20 is a reasonable starting point).
|
|
362
|
+
- Consider using tools like `join-monster` or `graphql-to-sql` that translate GraphQL queries directly into SQL JOINs, bypassing the resolver-per-field model entirely for database-backed schemas.
|
|
363
|
+
|
|
364
|
+
### 2. Query Cost Attacks (Denial of Service)
|
|
365
|
+
|
|
366
|
+
**What happens:** A malicious or careless client sends an expensive query. Two attack vectors: (1) deeply nested queries exploiting circular references (`user.posts.author.posts.author...` 20 levels deep), and (2) alias multiplication where the same expensive query is duplicated 100 times using GraphQL aliases (`a: users(first:1000) {...} b: users(first:1000) {...}`).
|
|
367
|
+
|
|
368
|
+
**Why it happens:** GraphQL gives the client control over query shape and depth. Without server-side limits, any field that is queryable can be nested or duplicated arbitrarily.
|
|
369
|
+
|
|
370
|
+
**How to prevent:**
|
|
371
|
+
- **Query depth limiting.** Reject queries deeper than N levels (typically 7-12).
|
|
372
|
+
- **Query cost analysis.** Assign costs to fields (scalar: 0, object: 1, list: 10, connection with `first`: `first * child_cost`). Reject queries exceeding a cost threshold. Shopify's approach: each field has a defined cost, and the total query cost is calculated before execution.
|
|
373
|
+
- **Persisted queries.** In production, only allow pre-registered query hashes. Clients send a hash, not the query text. Unknown hashes are rejected. This eliminates arbitrary queries entirely.
|
|
374
|
+
- **Rate limiting by query cost.** Traditional rate limiting counts requests. GraphQL rate limiting should count query cost: a simple query consuming 5 cost units and a complex query consuming 500 cost units should not be treated equally.
|
|
375
|
+
- **Timeout enforcement.** Set a hard timeout on query execution (e.g., 10 seconds). Kill any resolver chain that exceeds it.
|
|
376
|
+
|
|
377
|
+
### 3. Resolver Waterfall
|
|
378
|
+
|
|
379
|
+
**What happens:** Sequential resolver execution creates a waterfall pattern. A query for `user.organization.members.posts` resolves in four sequential steps: first the user, then the organization (waiting for the user), then the members (waiting for the organization), then the posts (waiting for the members). Each step adds latency.
|
|
380
|
+
|
|
381
|
+
**Why it happens:** GraphQL resolves fields depth-first. A child field cannot resolve until its parent has resolved. Unlike REST where the server controls query execution and can optimize the data-fetching order, GraphQL's resolver tree imposes a fixed resolution order dictated by the query structure.
|
|
382
|
+
|
|
383
|
+
**How to mitigate:**
|
|
384
|
+
- Design schemas to minimize depth. Flatten where possible.
|
|
385
|
+
- Use `@defer` directive (supported in Apollo Server 4+) to return shallow data immediately and stream deeper fields.
|
|
386
|
+
- Pre-compute common deep paths into denormalized fields.
|
|
387
|
+
- Use DataLoader to at least parallelize queries within each depth level.
|
|
388
|
+
|
|
389
|
+
### 4. Schema Complexity Creep
|
|
390
|
+
|
|
391
|
+
**What happens:** The schema grows organically over years. Types accumulate fields. Deprecated fields are never removed because "someone might be using them." The schema becomes a comprehensive mirror of every database table. New developers cannot understand the graph. Query auto-complete returns 200 fields for a type, most of which are legacy.
|
|
392
|
+
|
|
393
|
+
**Why it happens:** GraphQL's additive evolution model (add fields, deprecate old ones) makes it easy to grow a schema and hard to shrink it. Unlike REST where removing an endpoint version is a discrete event, removing a GraphQL field affects every client that uses it, and without persisted queries, you cannot know which clients use which fields.
|
|
394
|
+
|
|
395
|
+
**How to prevent:**
|
|
396
|
+
- Track field usage with schema analytics (Apollo Studio, GraphQL Hive). Remove fields that have zero usage over 90 days.
|
|
397
|
+
- Enforce schema review in CI: every schema change requires a pull request with a description of why the field exists and which client needs it.
|
|
398
|
+
- Set a field count budget per type (e.g., max 30 fields). If a type exceeds this, it needs to be decomposed.
|
|
399
|
+
- Use persisted queries in production so you have an exact inventory of which queries are in use.
|
|
400
|
+
|
|
401
|
+
### 5. Authorization Gaps
|
|
402
|
+
|
|
403
|
+
**What happens:** Field-level authorization is incomplete. A resolver for `User.email` checks authorization, but `User.phoneNumber` was added later without a check. A client queries `phoneNumber` directly and gets data they should not have access to.
|
|
404
|
+
|
|
405
|
+
**Why it happens:** REST authorization is per-endpoint. If you protect `/admin/users`, all fields in the response are protected. GraphQL authorization is per-field, and every new field is a new authorization surface. Developers who are accustomed to REST's endpoint-level model miss field-level checks.
|
|
406
|
+
|
|
407
|
+
**How to prevent:**
|
|
408
|
+
- Use a declarative authorization layer (`graphql-shield`, custom directives) that fails closed: fields without explicit authorization rules are rejected by default.
|
|
409
|
+
- Schema linting rules that flag any field without an authorization directive.
|
|
410
|
+
- Integration tests that attempt to access every field as an unauthorized user and verify denial.
|
|
411
|
+
|
|
412
|
+
### 6. Monitoring Blind Spots
|
|
413
|
+
|
|
414
|
+
**What happens:** The API returns HTTP 200 for all responses. The operations team sees 100% 200 responses and assumes the API is healthy. Meanwhile, 30% of responses contain errors in the `errors` array that nobody is monitoring.
|
|
415
|
+
|
|
416
|
+
**Why it happens:** GraphQL's error model is fundamentally different from REST. Existing monitoring infrastructure (Datadog, New Relic, CloudWatch) is built around HTTP status codes. A 200 response with errors requires custom extraction logic.
|
|
417
|
+
|
|
418
|
+
**How to prevent:**
|
|
419
|
+
- Instrument a custom metric for "GraphQL errors per operation" distinct from HTTP errors.
|
|
420
|
+
- Use Apollo Studio, GraphQL Hive, or a custom plugin that extracts operation names and error rates.
|
|
421
|
+
- Set up alerting on error rate per operation, not just per endpoint.
|
|
422
|
+
- Consider returning non-200 status codes for full query failures (authorization failures return 401, validation failures return 400) even though this deviates from the GraphQL spec.
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Technology Landscape
|
|
427
|
+
|
|
428
|
+
### Server Frameworks
|
|
429
|
+
|
|
430
|
+
| Technology | Language | Key Strength | Best For |
|
|
431
|
+
|---|---|---|---|
|
|
432
|
+
| **Apollo Server** | TypeScript/JS | Largest ecosystem, federation support, Apollo Studio integration | Teams using Apollo Client, federated architectures |
|
|
433
|
+
| **graphql-yoga** | TypeScript/JS | Lightweight, Envelop plugin system, built on modern standards (Fetch API) | Teams wanting modularity without Apollo lock-in |
|
|
434
|
+
| **Mercurius** | TypeScript/JS | Built on Fastify, JIT compilation, gateway mode | Performance-sensitive Node.js APIs |
|
|
435
|
+
| **Strawberry** | Python | Type-first using Python dataclasses, async support | Python teams, Django/FastAPI integration |
|
|
436
|
+
| **graphql-ruby** | Ruby | Mature, production-proven at GitHub and Shopify | Rails applications |
|
|
437
|
+
| **gqlgen** | Go | Code-first with code generation, strongly typed | Go services needing high performance |
|
|
438
|
+
| **Juniper** | Rust | Type-safe, compile-time schema validation | Rust services |
|
|
439
|
+
| **Hot Chocolate** | C# | .NET integration, filtering/sorting/pagination built-in | .NET enterprise applications |
|
|
440
|
+
| **Hasura** | Any (auto-generates) | Instant GraphQL API from PostgreSQL, real-time subscriptions | Rapid prototyping, PostgreSQL-centric apps |
|
|
441
|
+
| **PostGraphile** | PostgreSQL | Auto-generates from DB schema, extensible with plugins | PostgreSQL-first architectures, internal tools |
|
|
442
|
+
|
|
443
|
+
### Client Libraries
|
|
444
|
+
|
|
445
|
+
| Technology | Key Strength | Best For |
|
|
446
|
+
|---|---|---|
|
|
447
|
+
| **Apollo Client** | Normalized cache, devtools, largest ecosystem | React/React Native, teams using Apollo Server |
|
|
448
|
+
| **Relay** | Compiler-driven, fragment co-location, automatic pagination | Facebook-scale apps, teams committed to Relay's opinions |
|
|
449
|
+
| **urql** | Lightweight (~5KB), extensible via exchanges, framework-agnostic | Teams wanting simplicity over Apollo's feature set |
|
|
450
|
+
| **graphql-request** | Minimal (no cache, no framework integration), ~5KB | Simple scripts, server-to-server, Node.js clients |
|
|
451
|
+
| **TanStack Query + graphql-request** | Combines server-state management with GraphQL fetching | Teams already using TanStack Query for REST |
|
|
452
|
+
| **URQL + Graphcache** | Normalized caching with urql's simplicity | urql users who need Apollo-level caching |
|
|
453
|
+
|
|
454
|
+
### Schema Management and Tooling
|
|
455
|
+
|
|
456
|
+
| Tool | Purpose |
|
|
457
|
+
|---|---|
|
|
458
|
+
| **GraphQL Code Generator** | Generates TypeScript types, React hooks, resolvers from schema |
|
|
459
|
+
| **Apollo Studio / GraphOS** | Schema registry, field usage analytics, operation tracing |
|
|
460
|
+
| **GraphQL Hive** | Open-source schema registry, analytics, breaking change detection |
|
|
461
|
+
| **GraphQL Inspector** | CI tool for detecting breaking schema changes |
|
|
462
|
+
| **GraphQL ESLint** | Linting for schema and operations |
|
|
463
|
+
| **GraphiQL / Apollo Sandbox** | Interactive query editors with auto-complete and documentation |
|
|
464
|
+
| **Rover CLI** | Apollo's CLI for schema management and federation composition |
|
|
465
|
+
|
|
466
|
+
### Selection Guidance
|
|
467
|
+
|
|
468
|
+
**Starting out (solo/small team, learning GraphQL):** graphql-yoga + urql + GraphQL Code Generator. Minimal setup, modern defaults, no vendor lock-in.
|
|
469
|
+
|
|
470
|
+
**Production full-stack TypeScript:** Apollo Server + Apollo Client + GraphQL Code Generator + Apollo Studio. The most complete ecosystem with the largest community.
|
|
471
|
+
|
|
472
|
+
**Performance-critical Node.js:** Mercurius (built on Fastify) + urql. JIT query compilation and Fastify's performance.
|
|
473
|
+
|
|
474
|
+
**Rapid prototyping from a database:** Hasura or PostGraphile. Instant GraphQL API from PostgreSQL without writing resolvers. Extend with custom business logic as needed.
|
|
475
|
+
|
|
476
|
+
**Federated architecture at scale:** Apollo Router + subgraphs (any server framework per team) + Apollo Studio + Rover CLI. Or the open-source alternative: GraphQL Mesh + Hive.
|
|
477
|
+
|
|
478
|
+
**Python ecosystem:** Strawberry + strawberry-django for Django, or Ariadne for a schema-first approach.
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## Decision Tree
|
|
483
|
+
|
|
484
|
+
```
|
|
485
|
+
START: Do you need an API?
|
|
486
|
+
|
|
|
487
|
+
v
|
|
488
|
+
Is the primary use case simple CRUD with one client?
|
|
489
|
+
YES --> Use REST. GraphQL adds complexity without proportional benefit.
|
|
490
|
+
NO --> Continue.
|
|
491
|
+
|
|
|
492
|
+
v
|
|
493
|
+
Do multiple clients (web, mobile, third-party) need different data shapes?
|
|
494
|
+
YES --> Strong signal for GraphQL. Continue evaluating.
|
|
495
|
+
NO --> Is the data deeply nested (3+ levels of relationships)?
|
|
496
|
+
YES --> GraphQL may help. Continue evaluating.
|
|
497
|
+
NO --> REST is likely sufficient. Reconsider if data needs diversify.
|
|
498
|
+
|
|
|
499
|
+
v
|
|
500
|
+
Is HTTP caching critical to your performance requirements?
|
|
501
|
+
YES --> Can you implement application-level caching (Apollo Client, persisted queries)?
|
|
502
|
+
YES --> GraphQL is viable with additional caching work.
|
|
503
|
+
NO --> Stay with REST. GraphQL's caching model will be a persistent pain point.
|
|
504
|
+
NO --> Continue.
|
|
505
|
+
|
|
|
506
|
+
v
|
|
507
|
+
Is this a public API with untrusted consumers?
|
|
508
|
+
YES --> Can you implement query cost analysis, depth limiting, and persisted queries?
|
|
509
|
+
YES --> GraphQL is viable with security hardening.
|
|
510
|
+
NO --> Use REST. Untrusted consumers with unrestricted queries is a DoS vector.
|
|
511
|
+
NO --> Continue.
|
|
512
|
+
|
|
|
513
|
+
v
|
|
514
|
+
Does your team have GraphQL experience?
|
|
515
|
+
YES --> Proceed with GraphQL.
|
|
516
|
+
NO --> Do you have 2+ months runway before production launch?
|
|
517
|
+
YES --> Invest in learning. Start with a non-critical service.
|
|
518
|
+
NO --> Use REST now. Migrate to GraphQL when time permits.
|
|
519
|
+
|
|
|
520
|
+
v
|
|
521
|
+
How many backend services contribute data to client queries?
|
|
522
|
+
1-3 services --> Single GraphQL server with resolvers calling backend services.
|
|
523
|
+
4-10 services --> Consider federation. Evaluate team structure alignment.
|
|
524
|
+
10+ services --> Federation is strongly recommended. Each team owns their subgraph.
|
|
525
|
+
|
|
|
526
|
+
v
|
|
527
|
+
RESULT: Adopt GraphQL with the appropriate complexity level for your context.
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## Implementation Sketch
|
|
533
|
+
|
|
534
|
+
### Server with DataLoader (TypeScript, Apollo Server)
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
import { ApolloServer } from '@apollo/server';
|
|
538
|
+
import { startStandaloneServer } from '@apollo/server/standalone';
|
|
539
|
+
import DataLoader from 'dataloader';
|
|
540
|
+
|
|
541
|
+
// --- Request-scoped DataLoader factories (critical for N+1 prevention) ---
|
|
542
|
+
function createLoaders(db: Database) {
|
|
543
|
+
return {
|
|
544
|
+
userById: new DataLoader<string, User>(async (ids) => {
|
|
545
|
+
const users = await db.users.findByIds([...ids]);
|
|
546
|
+
const map = new Map(users.map(u => [u.id, u]));
|
|
547
|
+
return ids.map(id => map.get(id) ?? new Error(`User ${id} not found`));
|
|
548
|
+
}),
|
|
549
|
+
postsByAuthor: new DataLoader<string, Post[]>(async (authorIds) => {
|
|
550
|
+
const posts = await db.posts.findByAuthorIds([...authorIds]);
|
|
551
|
+
const grouped = groupBy(posts, p => p.authorId);
|
|
552
|
+
return authorIds.map(id => grouped.get(id) ?? []);
|
|
553
|
+
}),
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// --- Resolvers use loaders, never direct DB calls ---
|
|
558
|
+
const resolvers = {
|
|
559
|
+
Query: {
|
|
560
|
+
user: (_, { id }, ctx) => ctx.loaders.userById.load(id),
|
|
561
|
+
},
|
|
562
|
+
User: {
|
|
563
|
+
posts: (user, { first, after }, ctx) =>
|
|
564
|
+
ctx.loaders.postsByAuthor.load(user.id).then(p => paginate(p, { first, after })),
|
|
565
|
+
},
|
|
566
|
+
Post: {
|
|
567
|
+
author: (post, _, ctx) => ctx.loaders.userById.load(post.authorId),
|
|
568
|
+
},
|
|
569
|
+
Mutation: {
|
|
570
|
+
createPost: async (_, { input }, ctx) => {
|
|
571
|
+
if (!ctx.currentUser) return { post: null, errors: [{ field: '_', message: 'Auth required' }] };
|
|
572
|
+
const errors = validateCreatePost(input);
|
|
573
|
+
if (errors.length) return { post: null, errors };
|
|
574
|
+
const post = await ctx.db.posts.create({ ...input, authorId: ctx.currentUser.id });
|
|
575
|
+
return { post, errors: [] };
|
|
576
|
+
},
|
|
577
|
+
},
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
// --- Server: new loaders per request (prevents cross-user data leaks) ---
|
|
581
|
+
const server = new ApolloServer({ typeDefs, resolvers });
|
|
582
|
+
await startStandaloneServer(server, {
|
|
583
|
+
context: async ({ req }) => ({
|
|
584
|
+
currentUser: await authenticateFromHeader(req.headers.authorization),
|
|
585
|
+
db: getDatabase(),
|
|
586
|
+
loaders: createLoaders(getDatabase()),
|
|
587
|
+
}),
|
|
588
|
+
});
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
### Query Cost Analysis Plugin
|
|
592
|
+
|
|
593
|
+
```typescript
|
|
594
|
+
import { getComplexity, simpleEstimator, fieldExtensionsEstimator } from 'graphql-query-complexity';
|
|
595
|
+
|
|
596
|
+
// Apollo Server plugin — rejects queries exceeding cost threshold before execution
|
|
597
|
+
const queryComplexityPlugin = {
|
|
598
|
+
async requestDidStart() {
|
|
599
|
+
return {
|
|
600
|
+
async didResolveOperation({ request, document, schema }) {
|
|
601
|
+
const cost = getComplexity({
|
|
602
|
+
schema, query: document, variables: request.variables,
|
|
603
|
+
estimators: [fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 })],
|
|
604
|
+
});
|
|
605
|
+
if (cost > 1000) throw new GraphQLError(`Query cost ${cost} exceeds limit 1000.`);
|
|
606
|
+
},
|
|
607
|
+
};
|
|
608
|
+
},
|
|
609
|
+
};
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### Schema-Level Authorization (graphql-shield)
|
|
613
|
+
|
|
614
|
+
```typescript
|
|
615
|
+
import { shield, rule, and, or } from 'graphql-shield';
|
|
616
|
+
|
|
617
|
+
const isAuthenticated = rule()((_, __, ctx) => ctx.currentUser !== null);
|
|
618
|
+
const isAdmin = rule()((_, __, ctx) => ctx.currentUser?.role === 'ADMIN');
|
|
619
|
+
const isOwner = rule()((parent, _, ctx) => parent.authorId === ctx.currentUser?.id);
|
|
620
|
+
|
|
621
|
+
const permissions = shield({
|
|
622
|
+
Query: { '*': isAuthenticated },
|
|
623
|
+
Mutation: { createPost: isAuthenticated },
|
|
624
|
+
User: { email: and(isAuthenticated, or(isAdmin, isOwner)) },
|
|
625
|
+
}, { fallbackRule: isAuthenticated }); // Deny-by-default for unlisted fields
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
## Cross-References
|
|
631
|
+
|
|
632
|
+
- **[api-design-rest](../integration/api-design-rest.md)** — The alternative that GraphQL is most often compared to. REST is simpler, has better caching, and is the right default for most APIs. Understand REST deeply before choosing GraphQL.
|
|
633
|
+
- **[api-design-grpc](../integration/api-design-grpc.md)** — For service-to-service communication with strict performance requirements, gRPC (binary protocol, HTTP/2, streaming) is superior to both REST and GraphQL. GraphQL is for client-server; gRPC is for server-server.
|
|
634
|
+
- **[microservices](../patterns/microservices.md)** — GraphQL federation is an integration pattern for microservices. Understand microservice boundaries and team topology before adopting federation.
|
|
635
|
+
- **[data-modeling](../foundations/data-modeling.md)** — GraphQL schema design is a form of data modeling. A schema that mirrors database tables is as harmful as a REST API that mirrors tables. Model the domain, not the storage.
|
|
636
|
+
- **[hexagonal-clean-architecture](../patterns/hexagonal-clean-architecture.md)** — GraphQL resolvers are an adapter layer in hexagonal architecture. The resolver calls use cases; use cases call ports. Do not put business logic in resolvers.
|
|
637
|
+
- **[api-security](../../security/web/api-security.md)** — GraphQL introduces unique security concerns (query cost attacks, introspection exposure, field-level authorization) on top of standard API security (authentication, rate limiting, input validation).
|
|
638
|
+
- **[rate-limiting-and-throttling](../../performance/backend/rate-limiting-and-throttling.md)** — GraphQL rate limiting requires query-cost-based throttling rather than simple request counting. A query with cost 5 and a query with cost 500 should not consume the same rate limit budget.
|