How do you implement GraphQL APIs for flexible data fetching?
GraphQL provides a query language for APIs that lets clients request exactly the data they need. Core concepts: schema defines types and their relationships, queries fetch data, mutations modify data, subscriptions provide real-time updates, and resolvers implement the actual data fetching logic. When to use GraphQL: complex data relationships where clients need flexibility in what data they fetch, mobile applications needing to minimize data transfer, multiple client types (web, mobile, third-party) with different data needs, and rapid frontend development without backend API changes. Implementation: define schema types that model your domain (type User { id: ID!, name: String!, posts: [Post!]! }), implement resolvers that fetch data from databases, services, or other APIs, and handle the N+1 query problem with data loaders (batch and cache database queries). GraphQL with Supabase: Supabase automatically generates a GraphQL API from your PostgreSQL schema, supporting queries, mutations, filters, pagination, and relationships. For custom logic, implement resolver functions as edge functions. Performance: implement query complexity analysis (reject excessively deep or broad queries), use persisted queries (clients send a query ID instead of the full query, preventing arbitrary queries in production), implement dataloader for batching (resolve all User queries in a single SQL query rather than one per user), and cache query results with appropriate invalidation. Security: implement query depth limiting (prevent deeply nested queries that cause exponential data fetching), field-level authorization (check permissions per field in resolvers), rate limiting per client, and input validation for mutations. Pagination: use cursor-based pagination (more efficient for large datasets than offset-based), return page info with hasNextPage and endCursor, and implement connection pattern (edges with node and cursor).